﻿using System;
using System.Collections.Generic;
using Didaku.Attributes;
using Didaku.QEngine.Common.Counts;
using Didaku.QEngine.Common.Entities;
using Didaku.QEngine.Common.Enums;
using Didaku.QEngine.Common.EventArg;

namespace Didaku.QEngine.Common.Interfaces.Engine
{
    /// <summary>描述一个服务队列
    /// </summary>
    /// <remarks></remarks>
    public interface IServiceQueue<T> : ICloneable
        where T : Transaction
    {
        /// <summary>队列标识
        /// </summary>
        string Id { get; set; }

        /// <summary>助记编号（单网点唯一）
        /// </summary>
        string Number { get; set; }

        /// <summary>队列的表示元素，可以是业务,业务分类,客户类别,员工,等等
        /// </summary>
        List<IServiceQueueElement> Elements { get; set; }

        /// <summary>队列分段编码(号票前缀)
        /// </summary>
        [EntityColumn]
        string CallHead { get; set; }

        /// <summary>队列名称
        /// </summary>
        [EntityColumn]
        string Name { get; set; }

        /// <summary>号票长度(包含队列编码)
        /// </summary>
        [EntityColumn]
        ushort TicketLength { get; set; }

        /// <summary>当前队列最多可出票量，为0时表示不限制
        /// </summary>
        [EntityColumn]
        ushort TicketMaxCount { get; set; }

        /// <summary>号票起始数字
        /// </summary>
        /// <value>
        /// The ticket number start.
        /// </value>
        [EntityColumn]
        ushort TicketStartNumber { get; set; }

        /// <summary>号票终止数字
        /// </summary>
        /// <value>
        /// The ticket number end.
        /// </value>
        [EntityColumn]
        ushort TicketEndNumber { get; set; }

        /// <summary>计算指定的统计项目的交易数量
        /// </summary>
        /// <returns></returns>
        Count Calculate(TransactionStatus transactionStatus);

        /// <summary>生成一条新的交易<see cref="Transaction"/>
        /// </summary>
        /// <param name="currCount">输出:当前队列的号票计数</param>
        /// <returns></returns>
        T Generate(out int currCount);

        /// <summary>根据指定的条件返加最早加入的<see cref="Transaction"/>,并从队列中移除这个<see cref="Transaction"/>.
        /// </summary>
        /// <param name="transaction">输出:可办理的交易</param>
        /// <param name="func">指定的条件</param>
        /// <returns>如果有可办理的交易，返回真。否则反之。</returns>
        bool TryTake(out T transaction, Func<IEnumerable<T>, T> func);

        /// <summary>尝试根据指定的票号返回<see cref="Transaction"/>,并从队列中移除这个<see cref="Transaction"/>
        /// </summary>
        /// <param name="transaction">输出:可办理的交易</param>
        /// <param name="ticketNumber">指定的票号</param>
        /// <returns>如果有可办理的交易，返回真。否则反之。</returns>
        bool TrySearchRunning(string ticketNumber, out Transaction transaction);

        /// <summary>尝试根据指定的票号返回<see cref="Transaction"/>,并从队列中移除这个<see cref="Transaction"/>.当指定的条件为Null时,采用最基本的取票时间优先原则。
        /// </summary>
        /// <param name="ticketNumber">指定的票号</param>
        /// <param name="transaction">输出:可办理的交易, 该交易当前未被加入到队列中</param>
        /// <returns>如果有可办理的交易，返回真。否则反之。</returns>
        bool TrySearchClosed(string ticketNumber, out T transaction);

        /// <summary>向队列中添加一个新的交易<see cref="Transaction"/>,本方法中会激发新增事件
        /// </summary>
        /// <param name="tran">The tran.</param>
        /// <param name="isNewTransaction">被添加的交易是否是新的交易(可能是被转移过来的,就不属于新交易)</param>
        void Add(T tran, bool isNewTransaction);

        /// <summary>当队列中新增一条交易<see cref="Transaction"/>时发生的事件
        /// </summary>
        event ServiceQueueEventHandler TransactionAddedEvent;

        /// <summary>当队列中移除一条交易<see cref="Transaction"/>时发生的事件
        /// </summary>
        event ServiceQueueEventHandler TransactionRemovedEvent;

        /// <summary>当队列中一条交易<see cref="Transaction"/>的属性改变时发生的事件
        /// </summary>
        event ServiceQueueEventHandler TransactionChangedEvent;
    }
}